﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using HYCodeBase.Math;
using HYRevitCode.TransformUtility;

namespace HYRevitCode.XYZUtility
{
	public static class XYZUtilityMethod
	{
		public static XYZ SetX(this XYZ inputValue, double inputX)
		{
			if (inputValue == null)
			{
				return null;
			}
			return new XYZ(inputX, inputValue.Y, inputValue.Z);
		}

		public static XYZ SetY(this XYZ inputValue, double inputY)
		{
			if (inputValue == null)
			{
				return null;
			}
			return new XYZ(inputValue.X, inputY, inputValue.Z);
		}

		public static XYZ SetZ(this XYZ inputValue, double inputZ)
		{
			if (inputValue == null)
			{
				return null;
			}
			return new XYZ(inputValue.X, inputValue.Y, inputZ);
		}

		public static int PointInPloygon(List<Curve> lstCurves, XYZ pt)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curve in lstCurves)
			{
				XYZ item = curve.Evaluate(0.0, true);
				XYZ item2 = curve.Evaluate(0.5, true);
				XYZ item3 = curve.Evaluate(1.0, true);
				list.Add(item);
				list.Add(item2);
				list.Add(item3);
			}
			list = list.Distinct<XYZ>().ToList<XYZ>();
			return XYZUtilityMethod.PointInPloygon(list, pt);
		}

		public static int PointInPloygon(List<XYZ> vecPolypt, XYZ pt)
		{
			List<XYZ> range = vecPolypt.GetRange(0, vecPolypt.Count);
			if (range.Count < 3)
			{
				return -1;
			}
			XYZ xyz = range[0];
			XYZ xyz2 = range[range.Count - 1];
			if (xyz != xyz2)
			{
				range.Add(xyz);
			}
			int num = 0;
			List<XYZ> list = new List<XYZ>();
			XYZ xyz3 = new XYZ(0.0, 0.0, 0.0) - pt;
			for (int i = 0; i < range.Count; i++)
			{
				XYZ xyz4 = range[i];
				xyz4 += xyz3;
				list.Add(xyz4);
			}
			XYZ xyz5 = pt + xyz3;
			int num2 = MathUtility.Greaterthan_Or_Equal(list[0].X, 0.0) ? (MathUtility.Greaterthan_Or_Equal(list[0].Y, 0.0) ? 0 : 3) : (MathUtility.Greaterthan_Or_Equal(list[0].Y, 0.0) ? 1 : 2);
			for (int i = 1; i < list.Count; i++)
			{
				XYZ xyz6 = list[i - 1];
				XYZ xyz7 = list[i];
				if (MathUtility.IsEqual(xyz5.DistanceTo(xyz6), 0.0, 0.0001))
				{
					return 0;
				}
				XYZ xyz8 = new XYZ(xyz6.X, xyz6.Y, xyz6.Z);
				XYZ xyz9 = new XYZ(xyz7.X, xyz7.Y, xyz7.Z);
				xyz8 = xyz8.Normalize();
				xyz9 = xyz9.Normalize();
				double num3 = xyz9.Y * xyz8.X - xyz9.X * xyz8.Y;
				if (Math.Abs(num3) < 0.0001 && xyz8.X * xyz9.X <= 0.0001 && xyz8.Y * xyz9.Y <= 0.0001)
				{
					return 0;
				}
				int num4 = MathUtility.Greaterthan_Or_Equal(xyz7.X, 0.0) ? (MathUtility.Greaterthan_Or_Equal(xyz7.Y, 0.0) ? 0 : 3) : (MathUtility.Greaterthan_Or_Equal(xyz7.Y, 0.0) ? 1 : 2);
				if (num4 == (num2 + 1) % 4)
				{
					num++;
				}
				else if (num4 == (num2 + 2) % 4)
				{
					if (num3 > 0.0)
					{
						num += 2;
					}
					else
					{
						num -= 2;
					}
				}
				else if (num4 == (num2 + 3) % 4)
				{
					num--;
				}
				num2 = num4;
			}
			if (num == 0)
			{
				return -1;
			}
			if (Math.Abs(num) == 4)
			{
				return 1;
			}
			return 0;
		}

		public static bool Is_Points_Collinear(XYZ pt1, XYZ pt2, XYZ pt3, double tolerance = 1E-09)
		{
			double num = pt2.X - pt1.X;
			double num2 = pt2.Y - pt1.Y;
			double num3 = pt2.Z - pt1.Z;
			double num4 = pt3.X - pt1.X;
			double num5 = pt3.Y - pt1.Y;
			double num6 = pt3.Z - pt1.Z;
			double num7 = num2 * num6 - num5 * num3;
			double num8 = num4 * num3 - num * num6;
			double num9 = num * num5 - num4 * num2;
			return MathUtility.IsEqual(num7 * num7 + num8 * num8 + num9 * num9, 0.0, tolerance);
		}

		public static XYZ TransformPoint(XYZ point, Transform transform)
		{
			return TransformUtilityMethod.TransformPoint(point, transform);
		}

		public static XYZ CalculatMidPoint(XYZ ptStart, XYZ ptEnd)
		{
			XYZ xyz = ptEnd - ptStart;
			return ptStart + xyz / 2.0;
		}

		public static XYZ CalculatMidPoint(XYZ ptStart, XYZ ptEnd, XYZ ptCenter, XYZ normal)
		{
			if (MathUtility.LessThan(normal.Z, 0.0, 1E-09))
			{
				XYZ xyz = ptStart;
				ptStart = ptEnd;
				ptEnd = xyz;
			}
			double num = ptCenter.DistanceTo(ptStart);
			XYZ xyz2 = ptStart + (ptEnd - ptStart) / 2.0;
			XYZ xyz3 = (ptEnd - ptStart).Normalize();
			XYZ xyz4 = XYZ.BasisZ.CrossProduct(xyz3);
			if (XYZUtilityMethod.IsEqual(ptCenter, xyz2))
			{
				return ptCenter - xyz4 * num;
			}
			XYZ xyz5 = (ptCenter - xyz2).Normalize();
			if (XYZUtilityMethod.IsEqual(xyz5, xyz4))
			{
				return ptCenter - xyz5 * num;
			}
			return ptCenter + xyz5 * num;
		}

		public static XYZ UnBoundPlanarFaceProject(PlanarFace inputFace, XYZ inputPoint)
		{
			Transform transform = TransformUtilityMethod.CalculateTransformFromPlanarFaceToXoY(inputFace);
			XYZ xyz = TransformUtilityMethod.TransformPoint(inputFace.Origin, transform);
			return TransformUtilityMethod.TransformPoint(TransformUtilityMethod.TransformPoint(inputPoint, transform).SetZ(xyz.Z), transform.Inverse);
		}

		public static XYZ Abs(XYZ input)
		{
			if (input == null)
			{
				return null;
			}
			return new XYZ(Math.Abs(input.X), Math.Abs(input.Y), Math.Abs(input.Z));
		}

		public static bool IsEqual(XYZ pt1, XYZ pt2)
		{
			return MathUtility.IsEqual(pt1.DistanceTo(pt2), 0.0);
		}

		public static bool IsEqual(XYZ pt1, XYZ pt2, double eps)
		{
			return MathUtility.Lessthan_Or_Equal(pt1.DistanceTo(pt2), eps);
		}

		public static bool IsPointEqual(XYZ pt1, XYZ pt2, double precision)
		{
			return Math.Abs(pt1.X - pt2.X) < precision && Math.Abs(pt1.Y - pt2.Y) < precision && Math.Abs(pt1.Z - pt2.Z) < precision;
		}

		public static bool IsParallel(XYZ a, XYZ b)
		{
			double num = a.AngleTo(b);
			return 1E-09 > num || MathUtility.IsEqual(num, System.Math.PI);
		}

		public static bool IsParallel(XYZ a, XYZ b, double tolerance)
		{
			double num = a.AngleTo(b);
			return tolerance > num || MathUtility.IsEqual(num, System.Math.PI, tolerance);
		}

		public static bool IsVertical(XYZ a, XYZ b)
		{
			return MathUtility.IsEqual(a.AngleTo(b), System.Math.PI*.5);
		}

		public static XYZ CalculateFootPoint(XYZ ptStart, XYZ ptEnd, XYZ point)
		{
			if (MathUtility.IsEqual(ptStart.DistanceTo(ptEnd), 0.0))
			{
				return ptStart;
			}
			double num = Math.Sqrt((ptEnd.X - ptStart.X) * (ptEnd.X - ptStart.X) + (ptEnd.Y - ptStart.Y) * (ptEnd.Y - ptStart.Y) + (ptEnd.Z - ptStart.Z) * (ptEnd.Z - ptStart.Z));
			num = ((ptEnd.X - ptStart.X) * (point.X - ptStart.X) + (ptEnd.Y - ptStart.Y) * (point.Y - ptStart.Y) + (ptEnd.Z - ptStart.Z) * (point.Z - ptStart.Z)) / (num * num);
			double num2 = ptStart.X + (ptEnd.X - ptStart.X) * num;
			double num3 = ptStart.Y + (ptEnd.Y - ptStart.Y) * num;
			double num4 = ptStart.Z + (ptEnd.Z - ptStart.Z) * num;
			return new XYZ(num2, num3, num4);
		}

		public static XYZ CalculateFootPoint(XYZ ptStart, XYZ ptEnd, XYZ ptCenter, XYZ point)
		{
			double num = ptCenter.DistanceTo(ptStart);
			XYZ xyz = new XYZ(point.X, point.Y, ptCenter.Z) - ptCenter;
			xyz = xyz.Normalize() * num;
			return ptCenter + xyz;
		}

		public static bool IsPointInArea(List<Curve> area, XYZ pt)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curve in area)
			{
				list.AddRange(curve.Tessellate());
			}
			return XYZUtilityMethod.PointInPloygon(list, pt) == 1;
		}

		public static bool IsPointInCurve(Curve curve, XYZ point, bool ifUnBound = true)
		{
			Curve curve2 = curve.Clone();
			if (ifUnBound && curve2.IsBound)
			{
				curve2.MakeUnbound();
			}
			return point.IsAlmostEqualTo(curve2.Project(point).XYZPoint);
		}

		public static bool PointToString(XYZ point, out string pointString)
		{
			bool result;
			try
			{
				pointString = point.ToString();
				result = true;
			}
			catch
			{
				pointString = string.Empty;
				result = false;
			}
			return result;
		}

		public static bool StringToPoint(string pointString, out XYZ point)
		{
			bool result;
			try
			{
				pointString = pointString.Substring(1, pointString.Length - 2);
				string[] array = pointString.Split(new char[]
				{
					','
				});
				point = new XYZ(Convert.ToDouble(array[0]), Convert.ToDouble(array[1]), Convert.ToDouble(array[2]));
				result = true;
			}
			catch
			{
				point = null;
				result = false;
			}
			return result;
		}

		public static bool PointAtLineLeft(XYZ pt, XYZ ptStart, XYZ ptEnd)
		{
			double num = ptEnd.Y - ptStart.Y;
			double num2 = ptStart.X - ptEnd.X;
			double num3 = ptEnd.X * ptStart.Y - ptStart.X * ptEnd.Y;
			return num * pt.X + num2 * pt.Y + num3 < 0.0;
		}

		public static double GetAngle(XYZ ptCenter, XYZ ptOut)
		{
			XYZ xyz = ptOut - ptCenter;
			return MathUtility.formatAngle(XYZ.BasisX.AngleOnPlaneTo(xyz, XYZ.BasisZ));
		}

		public static bool Is_Point_OnSegment(XYZ ptSOfArc, XYZ ptEOfArc, XYZ ptCenterOfArc, XYZ normal, XYZ pt, double tolerance = 1E-09)
		{
			if (normal.Z < 0.0)
			{
				XYZ xyz = ptSOfArc;
				ptSOfArc = ptEOfArc;
				ptEOfArc = xyz;
			}
			double val = ptSOfArc.DistanceTo(ptCenterOfArc);
			double val2 = ptEOfArc.DistanceTo(ptCenterOfArc);
			if (!MathUtility.IsEqual(val, val2, tolerance))
			{
				return false;
			}
			double val3 = pt.DistanceTo(ptCenterOfArc);
			if (!MathUtility.IsEqual(val, val3, tolerance))
			{
				return false;
			}
			double angle = XYZUtilityMethod.GetAngle(ptCenterOfArc, ptSOfArc);
			double angle2 = XYZUtilityMethod.GetAngle(ptCenterOfArc, pt);
			double angle3 = XYZUtilityMethod.GetAngle(ptCenterOfArc, ptEOfArc);
			double num = MathUtility.BetweenTheAngles(angle, angle2, true);
			double num2 = MathUtility.BetweenTheAngles(angle2, angle3, true);
			return MathUtility.IsEqual(MathUtility.BetweenTheAngles(angle, angle3, true), num + num2, tolerance);
		}

		public static bool Is_Point_OnSegment(XYZ ptSOfLine, XYZ ptEOfLine, XYZ pt, double tolerance = 1E-09)
		{
			double x = ptSOfLine.X;
			double y = ptSOfLine.Y;
			double z = ptSOfLine.Z;
			double x2 = ptEOfLine.X;
			double y2 = ptEOfLine.Y;
			double z2 = ptEOfLine.Z;
			return ((MathUtility.Lessthan_Or_Equal(x, pt.X, tolerance) && MathUtility.Lessthan_Or_Equal(pt.X, x2, tolerance)) || (MathUtility.Lessthan_Or_Equal(x2, pt.X, tolerance) && MathUtility.Lessthan_Or_Equal(pt.X, x, tolerance))) && ((MathUtility.Lessthan_Or_Equal(y, pt.Y, tolerance) && MathUtility.Lessthan_Or_Equal(pt.Y, y2, tolerance)) || (MathUtility.Lessthan_Or_Equal(y2, pt.Y, tolerance) && MathUtility.Lessthan_Or_Equal(pt.Y, y, tolerance))) && ((MathUtility.Lessthan_Or_Equal(z, pt.Z, tolerance) && MathUtility.Lessthan_Or_Equal(pt.Z, z2, tolerance)) || (MathUtility.Lessthan_Or_Equal(z2, pt.Z, tolerance) && MathUtility.Lessthan_Or_Equal(pt.Z, z, tolerance))) && XYZUtilityMethod.Is_Points_Collinear(ptSOfLine, ptEOfLine, pt, tolerance);
		}

		public static int CompressArray(List<XYZ> lstPoint)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (XYZ xyz in lstPoint)
			{
				bool flag = false;
				foreach (XYZ pt in list)
				{
					if (XYZUtilityMethod.IsPointEqual(xyz, pt, 1E-05))
					{
						flag = true;
					}
				}
				if (!flag)
				{
					list.Add(xyz);
				}
			}
			lstPoint.Clear();
			foreach (XYZ item in list)
			{
				lstPoint.Add(item);
			}
			return lstPoint.Count;
		}

		public static bool IsSameDirection(XYZ firstVec, XYZ secondVec)
		{
			XYZ xyz = firstVec.Normalize();
			XYZ xyz2 = secondVec.Normalize();
			return MathUtility.IsEqual(xyz.DotProduct(xyz2), 1.0, 1E-05);
		}

		public static bool IsOppositeDirection(XYZ firstVec, XYZ secondVec)
		{
			XYZ xyz = firstVec.Normalize();
			XYZ xyz2 = secondVec.Normalize();
			return MathUtility.IsEqual(xyz.DotProduct(xyz2), -1.0, 1E-05);
		}

		public static int GetPointQuadrant(XYZ ptStart, XYZ ptEnd, XYZ ptTest)
		{
			XYZ xyz = (ptEnd - ptStart).Normalize();
			XYZ xyz2 = RevitVersionFuncs.CreateRotationAtPoint(-XYZ.BasisZ, System.Math.PI*.5, ptStart).OfVector(xyz);
			XYZ xyz3 = (ptStart + ptEnd) / 2.0;
			XYZ xyz4 = (ptTest - xyz3).Normalize();
			double num = xyz4.DotProduct(xyz2);
			double num2 = xyz4.DotProduct(xyz);
			if (num > -1E-05 && num2 > 0.0)
			{
				return 1;
			}
			if (num < 0.0 && num2 > -1E-05)
			{
				return 2;
			}
			if (num < 1E-05 && num2 < 0.0)
			{
				return 3;
			}
			if (num > 0.0 && num2 < 1E-05)
			{
				return 4;
			}
			return 0;
		}

		public static void GetPolyBoundPts(List<XYZ> lstPoints, ref XYZ ptMin, ref XYZ ptMax)
		{
			double num = 0.0;
			double num2 = 0.0;
			double num3 = 0.0;
			double num4 = 0.0;
			for (int i = 0; i < lstPoints.Count; i++)
			{
				XYZ xyz = lstPoints.ElementAt(i);
				if (i == 0)
				{
					num = xyz.X;
					num2 = xyz.Y;
					num3 = xyz.X;
					num4 = xyz.Y;
				}
				else
				{
					if (xyz.X < num)
					{
						num = xyz.X;
					}
					if (xyz.Y < num2)
					{
						num2 = xyz.Y;
					}
					if (xyz.X > num3)
					{
						num3 = xyz.X;
					}
					if (xyz.Y > num4)
					{
						num4 = xyz.Y;
					}
				}
			}
			ptMin = new XYZ(num, num2, ptMin.Z);
			ptMax = new XYZ(num3, num4, ptMax.Z);
		}

		public static XYZ RotateTo(XYZ vt, XYZ origin, double angle, XYZ axis)
		{
			if (XYZUtilityMethod.IsEqual(vt, XYZ.Zero, 0.0001))
			{
				return vt;
			}
			Transform transform = RevitVersionFuncs.CreateRotationAtPoint(axis, angle, origin);
			return XYZUtilityMethod.TransformPoint(vt, transform);
		}

		public static XYZ RotateTo(XYZ vt, double angle, XYZ axis)
		{
			return XYZUtilityMethod.RotateTo(vt, XYZ.Zero, angle, axis);
		}

		public static XYZ Get2DXYZ(XYZ point3d)
		{
			return new XYZ(point3d.X, point3d.Y, 0.0);
		}

		public const double _epsPoint = 0.0001;

		public const double _archPrecision = 1E-05;
	}
}
